#pragma once
/*
 * Created by: Mark Lavrynenko
 * Email:	MarkLavrinenko@gmail.com
 * Project:	  Huffman
*/

#include <stdint.h>
#include <memory.h>
#include <vector>
#include <assert.h>
#include <DataTarget.h>

using std::vector;

class BitSequence
{
public:
	BitSequence(const vector<char> &bits)
	{
		m_size = bits.size();
		m_block_count = m_size / sizeof(T)  + (0 != m_size % sizeof(T)) ? 1 : 0;
		m_buffer = new T[m_block_count];
		memset(m_buffer, (uint8_t)0, m_block_count);
	
		size_t j = 0;			// block
		size_t bit = 7;		// bit number from 7 to 0
		for (size_t i = 0; i < m_size; ++i)
		{
			assert(j < m_block_count);
			assert('0' == bits[i] || '1' == bits[i]);
			if ('1' == bits[i])
				m_buffer[j] |= (1 << bit);
			--bit;
			if (bit < 0)
			{
				bit = 7;
				++j;
			}
		}
	}

	~BitSequence()
	{
		delete [] m_buffer;
	}
	
	inline void  serializeInto(DataTarget* dt) const
	{
		const T* t = m_buffer;
		size_t size = m_size / ( 8 * sizeof(T));
		for (size_t i = 0; i < size;  ++i, ++t)
		{
			dt->putNextByte(*t);
		}
		size_t rest = m_size % sizeof(T);
		if (rest)
		{
			size_t bit = 7;
			for (size_t i = 0; i < rest; ++i, --bit)
			{
				dt->putNextBit(0 != m_buffer[size] & (1 << bit));
			}				
		}		
	}

private:
	typedef int8_t T;						// do not change!!!!!!!
	T* m_buffer;
	size_t m_size;							// pretended size in bits
	size_t m_block_count;				// number of blocks of type T	
};

